home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / libs / db / db-1.85 / db-1 / db.1.85.4 / recno / rec_open.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-03-10  |  7.4 KB  |  272 lines

  1. /*-
  2.  * Copyright (c) 1990, 1993, 1994
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Mike Olson.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36.  
  37. #if defined(LIBC_SCCS) && !defined(lint)
  38. static char sccsid[] = "@(#)rec_open.c    8.10 (Berkeley) 9/1/94";
  39. #endif /* LIBC_SCCS and not lint */
  40.  
  41. #include <sys/types.h>
  42. #include <sys/mman.h>
  43. #include <sys/stat.h>
  44.  
  45. #include <errno.h>
  46. #include <fcntl.h>
  47. #include <limits.h>
  48. #include <stddef.h>
  49. #include <stdio.h>
  50. #include <unistd.h>
  51.  
  52. #if defined(linux)
  53. #include <sys/utsname.h>
  54. #define MMAP_VERSION "1.3.50"
  55. #endif
  56.  
  57. #include <db.h>
  58. #include "recno.h"
  59.  
  60. DB *
  61. __rec_open(fname, flags, mode, openinfo, dflags)
  62.     const char *fname;
  63.     int flags, mode, dflags;
  64.     const RECNOINFO *openinfo;
  65. {
  66.     BTREE *t;
  67.     BTREEINFO btopeninfo;
  68.     DB *dbp;
  69.     PAGE *h;
  70.     struct stat sb;
  71.     int rfd, sverrno;
  72. #if defined(linux)
  73.     struct utsname buf;
  74. #endif
  75.  
  76.     /* Open the user's file -- if this fails, we're done. */
  77.     if (fname != NULL && (rfd = open(fname, flags, mode)) < 0)
  78.         return (NULL);
  79.  
  80.     /* Create a btree in memory (backed by disk). */
  81.     dbp = NULL;
  82.     if (openinfo) {
  83.         if (openinfo->flags & ~(R_FIXEDLEN | R_NOKEY | R_SNAPSHOT))
  84.             goto einval;
  85.         btopeninfo.flags = 0;
  86.         btopeninfo.cachesize = openinfo->cachesize;
  87.         btopeninfo.maxkeypage = 0;
  88.         btopeninfo.minkeypage = 0;
  89.         btopeninfo.psize = openinfo->psize;
  90.         btopeninfo.compare = NULL;
  91.         btopeninfo.prefix = NULL;
  92.         btopeninfo.lorder = openinfo->lorder;
  93.         dbp = __bt_open(openinfo->bfname,
  94.             O_RDWR, S_IRUSR | S_IWUSR, &btopeninfo, dflags);
  95.     } else
  96.         dbp = __bt_open(NULL, O_RDWR, S_IRUSR | S_IWUSR, NULL, dflags);
  97.     if (dbp == NULL)
  98.         goto err;
  99.  
  100.     /*
  101.      * Some fields in the tree structure are recno specific.  Fill them
  102.      * in and make the btree structure look like a recno structure.  We
  103.      * don't change the bt_ovflsize value, it's close enough and slightly
  104.      * bigger.
  105.      */
  106.     t = dbp->internal;
  107.     if (openinfo) {
  108.         if (openinfo->flags & R_FIXEDLEN) {
  109.             F_SET(t, R_FIXLEN);
  110.             t->bt_reclen = openinfo->reclen;
  111.             if (t->bt_reclen == 0)
  112.                 goto einval;
  113.         }
  114.         t->bt_bval = openinfo->bval;
  115.     } else
  116.         t->bt_bval = '\n';
  117.  
  118.     F_SET(t, R_RECNO);
  119.     if (fname == NULL)
  120.         F_SET(t, R_EOF | R_INMEM);
  121.     else
  122.         t->bt_rfd = rfd;
  123.  
  124.     if (fname != NULL) {
  125.         /*
  126.          * In 4.4BSD, stat(2) returns true for ISSOCK on pipes.
  127.          * Unfortunately, that's not portable, so we use lseek
  128.          * and check the errno values.
  129.          */
  130.         errno = 0;
  131.         if (lseek(rfd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE) {
  132.             switch (flags & O_ACCMODE) {
  133.             case O_RDONLY:
  134.                 F_SET(t, R_RDONLY);
  135.                 break;
  136.             default:
  137.                 goto einval;
  138.             }
  139. slow:            if ((t->bt_rfp = fdopen(rfd, "r")) == NULL)
  140.                 goto err;
  141.             F_SET(t, R_CLOSEFP);
  142.             t->bt_irec =
  143.                 F_ISSET(t, R_FIXLEN) ? __rec_fpipe : __rec_vpipe;
  144.         } else {
  145.             switch (flags & O_ACCMODE) {
  146.             case O_RDONLY:
  147.                 F_SET(t, R_RDONLY);
  148.                 break;
  149.             case O_RDWR:
  150.                 break;
  151.             default:
  152.                 goto einval;
  153.             }
  154.  
  155.             if (fstat(rfd, &sb))
  156.                 goto err;
  157.             /*
  158.              * Kluge -- we'd like to test to see if the file is too
  159.              * big to mmap.  Since, we don't know what size or type
  160.              * off_t's or size_t's are, what the largest unsigned
  161.              * integral type is, or what random insanity the local
  162.              * C compiler will perpetrate, doing the comparison in
  163.              * a portable way is flatly impossible.  Hope that mmap
  164.              * fails if the file is too large.
  165.              */
  166.             if (sb.st_size == 0)
  167.                 F_SET(t, R_EOF);
  168.             else {
  169. #ifdef MMAP_NOT_AVAILABLE
  170.                 /*
  171.                  * XXX
  172.                  * Mmap doesn't work correctly on many current
  173.                  * systems.  In particular, it can fail subtly,
  174.                  * with cache coherency problems.  Don't use it
  175.                  * for now.
  176.                  */
  177.                 t->bt_msize = sb.st_size;
  178. /*
  179.  * hack : 
  180.  *
  181.  * The Linux kernel mmap() semantics are broken under version 1.2 and
  182.  * early 1.3 kernels :
  183.  * 
  184.  * Under Linux, read only private mappings cause write only and read/write 
  185.  * opens to fail with errno=ETXTBSY.  Shared read only mappings should work
  186.  * fine though, but I'm not familiar enough with the code to ascertain that
  187.  * a MAP_SHARED mapping would be safe so I use the non-mmap'd version 
  188.  * instead.
  189.  *
  190.  */
  191.  
  192. #if defined(linux) 
  193.                 if ( uname( &utsbuf ) && 
  194.                      ( strcmp( utsbuf.release, MMAP_VERSION ) >= 0 ) )
  195. #endif
  196.                     if ((t->bt_smap = mmap(NULL, t->bt_msize,
  197.                                    PROT_READ, MAP_PRIVATE, rfd,
  198.                                    (off_t)0)) == (caddr_t)-1)
  199.                         goto slow;
  200. #if defined(linux)
  201.                 else
  202.                     goto slow;
  203. #endif
  204.                 t->bt_cmap = t->bt_smap;
  205.                 t->bt_emap = t->bt_smap + sb.st_size;
  206.                 t->bt_irec = F_ISSET(t, R_FIXLEN) ?
  207.                     __rec_fmap : __rec_vmap;
  208.                 F_SET(t, R_MEMMAPPED);
  209. #else
  210.                 goto slow;
  211. #endif
  212.             }
  213.         }
  214.     }
  215.  
  216.     /* Use the recno routines. */
  217.     dbp->close = __rec_close;
  218.     dbp->del = __rec_delete;
  219.     dbp->fd = __rec_fd;
  220.     dbp->get = __rec_get;
  221.     dbp->put = __rec_put;
  222.     dbp->seq = __rec_seq;
  223.     dbp->sync = __rec_sync;
  224.  
  225.     /* If the root page was created, reset the flags. */
  226.     if ((h = mpool_get(t->bt_mp, P_ROOT, 0)) == NULL)
  227.         goto err;
  228.     if ((h->flags & P_TYPE) == P_BLEAF) {
  229.         F_CLR(h, P_TYPE);
  230.         F_SET(h, P_RLEAF);
  231.         mpool_put(t->bt_mp, h, MPOOL_DIRTY);
  232.     } else
  233.         mpool_put(t->bt_mp, h, 0);
  234.  
  235.     if (openinfo && openinfo->flags & R_SNAPSHOT &&
  236.         !F_ISSET(t, R_EOF | R_INMEM) &&
  237.         t->bt_irec(t, MAX_REC_NUMBER) == RET_ERROR)
  238.                 goto err;
  239.     return (dbp);
  240.  
  241. einval:    errno = EINVAL;
  242. err:    sverrno = errno;
  243.     if (dbp != NULL)
  244.         (void)__bt_close(dbp);
  245.     if (fname != NULL)
  246.         (void)close(rfd);
  247.     errno = sverrno;
  248.     return (NULL);
  249. }
  250.  
  251. int
  252. __rec_fd(dbp)
  253.     const DB *dbp;
  254. {
  255.     BTREE *t;
  256.  
  257.     t = dbp->internal;
  258.  
  259.     /* Toss any page pinned across calls. */
  260.     if (t->bt_pinned != NULL) {
  261.         mpool_put(t->bt_mp, t->bt_pinned, 0);
  262.         t->bt_pinned = NULL;
  263.     }
  264.  
  265.     /* In-memory database can't have a file descriptor. */
  266.     if (F_ISSET(t, R_INMEM)) {
  267.         errno = ENOENT;
  268.         return (-1);
  269.     }
  270.     return (t->bt_rfd);
  271. }
  272.